/*************************************************************************
                           Dictionnaire  -  description
                        -------------------

*************************************************************************/

//---------- Réalisation de la classe <Reseau> (fichier Reseau.cpp) --

//---------------------------------------------------------------- INCLUDE

//-------------------------------------------------------- Include système
using namespace std;
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <math.h>

//------------------------------------------------------ Include personnel
#include "Reseau.h"

//------------------------------------------------------------- Constantes

//----------------------------------------------------------------- PUBLIC

//----------------------------------------------------- Méthodes publiques

void Reseau::Save( ofstream & file )
{
    for (int i = 0 ; i < NEURONES_ENTREE ;  i++)
    {
        for (int j = 0 ; j < NEURONES_INTER ;j++)
        {
            file.write ( (char*) &poids1[i][j], sizeof ( poids1[i][j] ) );
        }
    }
    for (int i = 0 ; i < NEURONES_INTER ;  i++)
    {
        for(int j = 0 ; j < NEURONES_SORTIE ;j++)
        {
            file.write ( (char*) &poids2[i][j], sizeof ( poids2[i][j] ) );
        }
    }
}

void Reseau::Load ( ifstream & file )
{
    for(int i = 0 ; i < NEURONES_ENTREE ;  i++)
    {
        for(int j = 0 ; j < NEURONES_INTER ;j++)
        {
            file.read ( (char*) &poids1[i][j], sizeof ( poids1[i][j] ) );
        }
    }
    for(int i = 0 ; i < NEURONES_INTER ;  i++)
    {
        for(int j = 0 ; j < NEURONES_SORTIE ;j++)
        {
            file.read ( (char*) &poids2[i][j], sizeof ( poids2[i][j] ) );
        }
    }
}

void Reseau::AfficherNeuronesSortie()
{
  
  for(int i=0; i < NEURONES_SORTIE ; i++)
  {
    cout << "vitesse " << couche_sortie[0][i] << endl;
  }
    
}

double * Reseau::GetNeuronesSortie()
{
  
  for(int i=0; i < NEURONES_SORTIE ; i++)
  {
    resultat[i] = couche_sortie[0][i];
  }
  return resultat;
}

void Reseau::ModifierPoids1(int ligne,int colonne, double poids)
{
    poids1[ligne][colonne] = poids;
}

void Reseau::ModifierPoids2(int ligne, int colonne, double poids)
{
    poids2[ligne][colonne] = poids;
}

void Reseau::ConstruireReseau()
{
    couche_externe[0][NEURONES_ENTREE - 1] = 1;//neurone de seuil
    //remplissage aléatoire des poids synaptiques
    for(int i = 0 ; i < NEURONES_ENTREE -1 ; i++)
    {
        for(int j = 0 ; j < NEURONES_INTER ; j++)
        {
            int indice = 1 + int( double( rand() ) / ( double( RAND_MAX) + 1 ) * 10.0 );
            double indice2;
            indice2 = pow(-1,indice);
            poids1[i][j] = indice2*(1 + ( double( rand() ) / ( double( RAND_MAX) + 1 ) * 10.0 ))/10.0;
        }
    }
    //initialisation de la couche cachée
    for(int i = 0 ; i < NEURONES_INTER ; i++)
    {
        couche_cachee[0][i] = 0;
    }

    for(int i = 0 ; i < NEURONES_INTER ; i++)
    {
        for(int j = 0 ; j < NEURONES_SORTIE ; j++)
        {
            int indice = 1 + int( double( rand() ) / ( double( RAND_MAX) + 1 ) * 10.0 );
            double indice2;
            indice2 = pow(-1,indice);
            poids2[i][j] = indice2*(1 + ( double( rand() ) / ( double( RAND_MAX) + 1 ) * 10.0 ))/10.0;
        }
    }
}

void Reseau::ConstruireReseau ( double unPoids1[NEURONES_ENTREE][NEURONES_INTER], double unPoids2[NEURONES_INTER][NEURONES_SORTIE])
{
    couche_externe[0][NEURONES_ENTREE -1] = 1; //neurone de seuil
    for(int i = 0 ; i < NEURONES_ENTREE - 1 ;  i++)
    {
        for(int j = 0 ; j < NEURONES_INTER ;j++)
        {
            poids1[i][j] =  unPoids1[i][j];
        }
    }
    for(int i = 0 ; i < NEURONES_INTER ;  i++)
    {
        for(int j = 0 ; j < NEURONES_SORTIE ;j++)
        {
            poids2[i][j] =  unPoids2[i][j];
        }
    }
}

// void Reseau::CalculerCoucheSortie(double infoCapteurs[1][50])
void Reseau::CalculerCoucheSortie(double * infoCapteurs)
{
    //récupération des données venant des capteurs
    for(int i = 0 ; i < NEURONES_ENTREE - 1 ; i++)
    {
        couche_externe[0][i] = infoCapteurs[i];
    }
    //neurone "de seuil"
    couche_externe[0][NEURONES_ENTREE - 1] = 1;

    for(int i = 0 ; i < NEURONES_SORTIE ; i++)
    {
      couche_sortie[0][i] = 0;
    }
    

    // Calcul des etats de neurones de la couche cachée
    double neuroneEntree;
    for(int i=0;i < 1;i++)
    {
        for(int j=0;j < NEURONES_INTER;j++)
        {
            neuroneEntree = 0;
            for(int k=0;k<NEURONES_ENTREE;k++)
            {
                neuroneEntree += couche_externe[i][k]*poids1[k][j];

            }
            neuroneEntree += couche_externe[0][NEURONES_ENTREE];
            couche_cachee[i][j] = 1/(1+exp(-neuroneEntree));
        }
    }
    // Calcule des etats des neurones de sortie
    for(int j=0;j<NEURONES_SORTIE;j++)
    {
        neuroneEntree = 0;
        for(int k=0;k<NEURONES_INTER;k++)
        {
            neuroneEntree += couche_cachee[0][k]*poids2[k][j];
        }
        couche_sortie[0][j] = 1 / (1+ exp(-neuroneEntree));
    };
//     couche_sortie[0][0] = sqrt(couche_sortie[0][0] * couche_sortie[0][0]);
}


void Reseau::Print()
{
	cout << "Poids entree inter" << endl;
	for(int i=0; i<NEURONES_ENTREE; i++)
	{
		for (int j=0; j<NEURONES_INTER; j++)
		{
			cout << poids1[i][j] << "      " ;
		}
	cout << endl;
	}
	cout << endl << endl << endl;
	cout << "Poids Inter Sortie " << endl;
	for(int i=0; i<NEURONES_INTER; i++)
	{
		for (int j=0; j<NEURONES_SORTIE; j++)
		{
			cout << poids2[i][j] << "      " ;
		}
	cout << endl;
	}
}



//------------------------------------------------- Surcharge d'opérateurs
Reseau & Reseau::operator = ( const Reseau  & unReseau )
{
    couche_externe[0][NEURONES_ENTREE] = 1;
    for(int i = 0 ; i < NEURONES_ENTREE ;  i++)
    {
        for(int j = 0 ; j < NEURONES_INTER ;j++)
        {
            poids1[i][j] = unReseau.poids1[i][j];
        }
    }
    for(int i = 0 ; i < NEURONES_INTER ;  i++)
    {
        for(int j = 0 ; j < NEURONES_SORTIE ;j++)
        {
            poids2[i][j] = unReseau.poids2[i][j];
        }
    }
    return *this;
}

//-------------------------------------------- Constructeurs - destructeur

Reseau::Reseau ( const Reseau  & unReseau )
{
    couche_externe[0][NEURONES_ENTREE] = 1;
    for(int i = 0 ; i < NEURONES_ENTREE ;  i++)
    {
        for(int j = 0 ; j < NEURONES_INTER ;j++)
        {
            poids1[i][j] = unReseau.poids1[i][j];
        }
    }
    for(int i = 0 ; i < NEURONES_INTER ;  i++)
    {
        for(int j = 0 ; j < NEURONES_SORTIE ;j++)
        {
            poids2[i][j] = unReseau.poids2[i][j];
        }
    }
}

Reseau::Reseau( )
{
    ConstruireReseau();
//     couche_externe[0][50] = 1;
//     for(int i = 0 ; i < 50 ;  i++)
//     {
//         for(int j = 0 ; j < 20 ;j++)
//         {
//             poids1[i][j] = 0;
//         }
//     }
//     for(int i = 0 ; i < 20 ;  i++)
//     {
//         for(int j = 0 ; j < 2 ;j++)
//         {
//             poids2[i][j] = 0;
//         }
//     }
}

Reseau::~Reseau( )
{
}

//------------------------------------------------------------------ PRIVE

//----------------------------------------------------- Méthodes protégées
